<?php

namespace ChainOfResponsibilityPattern;

/**
 * 责任链模式的具体角色和职责
 * 1. 抽象处理者：声明一个处理请求的接口，并持有对下一个处理者的引用
 * 2. 具体处理者：实现抽象处理者的方法，如果当前请求能够处理，则处理，否则转发给下一个处理者
 */

// 以订单优惠处理为例，用责任链模式实现一个简单的订单优惠系统
// 为什么不用策略模式呢，因为策略模式是类似if...else...这种选择一个分支去处理
// 而这里的例子则是交叉、组合的，可以是满减和会员折扣一起使用，此时就不太适合策略模式了

// 1. 定义抽象处理者
interface DiscountHandler
{
    public function setNextHandler(DiscountHandler $discountHandler): void;
    public function applyDiscount(Order $order): void;
}

// 定义订单类
class Order
{
    private float $amount;
    private bool $hasCoupon;
    private bool $isMember;
    public function __construct(float $amount, bool $hasCoupon, bool $isMember)
    {
        $this->amount = $amount;
        $this->hasCoupon = $hasCoupon;
        $this->isMember = $isMember;
    }

    public function setAmount(float $amount): void
    {
        $this->amount = $amount;
    }

    public function getAmount(): float
    {
        return $this->amount;
    }

    public function setHasCoupon(): void
    {
        $this->hasCoupon = !$this->hasCoupon;
    }
    public function hasCoupon(): bool
    {
        return $this->hasCoupon;
    }

    public function isMember(): bool
    {
        return $this->isMember;
    }
}

// 2. 定义责任链节点

// 满减责任链节点
class FullReductionDiscountHandler implements DiscountHandler
{
    private DiscountHandler $nextHandler;
    public function setNextHandler(DiscountHandler $discountHandler): void
    {
        $this->nextHandler = $discountHandler;
    }

    public function applyDiscount(Order $order): void
    {
        echo "【进入责任链节点】满减折扣 \n";
        $amount = $order->getAmount();
        if ($amount >= 100) {
            $amount = $amount - 20;
            echo "【满减折扣】-20 \n";
            $order->setAmount($amount);
            echo "【优惠券折扣】-20 当前价格 $amount \n";
        }
        if (!empty($this->nextHandler)) {
            echo "传递给下一个责任链节点 \n";
            $this->nextHandler->applyDiscount($order);
        }
    }
}

//优惠券责任链节点
class CouponDiscountHandler implements DiscountHandler
{
    private DiscountHandler $nextHandler;
    public function setNextHandler(?DiscountHandler $discountHandler): void
    {
        $this->nextHandler = $discountHandler;
    }

    public function applyDiscount(Order $order): void
    {
        echo "【进入责任链节点】优惠券折扣 \n";
        // 没有使用过优惠券，则使用
        if (!$order->hasCoupon()) {
            $order->setAmount(max($order->getAmount() - 20, 0));
            $amount = $order->getAmount();
//            $order->setHasCoupon();
            echo "【优惠券折扣】-20 当前价格 $amount \n";
        } else {
            echo "【未使用优惠券】 \n";
        }

        if (!empty($this->nextHandler)) {
            echo "传递给下一个责任链节点 \n";
            $this->nextHandler->applyDiscount($order);
        }
    }
}

//会员责任链节点
class MemberDiscountHandler implements DiscountHandler
{
    private DiscountHandler $nextHandler;
    public function setNextHandler(DiscountHandler $discountHandler): void
    {
        $this->nextHandler = $discountHandler;
    }

    public function applyDiscount(Order $order): void
    {
        echo "【进入责任链节点】会员折扣 \n";
        // 没有使用过优惠券，则使用
        if ($order->isMember()) {
            $order->setAmount($order->getAmount() * 0.8);
            echo "【会员折扣】八折 \n";
        } else {
            echo "【该用户不是会员】 \n";
        }

        if (!empty($this->nextHandler)) {
            echo "传递给下一个责任链节点 \n";
            $this->nextHandler->applyDiscount($order);
        }
    }
}

//测试
// 定义订单属性
$order = new Order(100, !!0, !!1);
// 实例化三个责任链节点
$fullReductionDiscountHandler = new FullReductionDiscountHandler();
$couponDiscountHandler = new CouponDiscountHandler();
$memberDiscountHandler = new MemberDiscountHandler();
// 定义责任链顺序，哪个折扣比较优先
echo "满减折扣-->优惠券-->会员折扣\n";
$couponDiscountHandler->setNextHandler($memberDiscountHandler);
$fullReductionDiscountHandler->setNextHandler($couponDiscountHandler);
$fullReductionDiscountHandler->applyDiscount($order);
$amount = $order->getAmount();
echo "【最终价格1==================================】$amount\n";

echo "优惠券-->满减折扣-->会员折扣\n";
$order->setAmount(100);
$fullReductionDiscountHandler->setNextHandler($memberDiscountHandler);
$couponDiscountHandler->setNextHandler($fullReductionDiscountHandler);
$couponDiscountHandler->applyDiscount($order);
$amount = $order->getAmount();
echo "【最终价格2==================================】$amount\n";

echo "会员折扣-->满减折扣-->优惠券\n";
$order->setAmount(100);
$fullReductionDiscountHandler->setNextHandler(new CouponDiscountHandler());
$memberDiscountHandler->setNextHandler($fullReductionDiscountHandler);
$memberDiscountHandler->applyDiscount($order);
$amount = $order->getAmount();
echo "【最终价格3==================================】$amount\n";